package tlog

import (
	"context"
	"os"
	"path/filepath"
)

const logpath = "/log"

type logConf struct {
	testenv          bool
	processName      string
	logPath          string
	clearHistoryLog  bool   // 是否先清理旧的日志文件
	logLevel         string // 日志级别
	listenAddr       string
	encodeing        string // json console [todo add more]
	targetName       string // stdout syslog asyncfile ...
	logFilePath      string // default "../log"
	logFileRotate    string // default no option [date,hour]
	HostName         string
	ElkTemplateName  string //区分不同业务
	logTimestampMs   bool
	functionKey      string
	traceIDExtractor func(ctx context.Context) string // 获取traceId
}

var defaultLogOptions = logConf{
	testenv:          true,
	processName:      filepath.Base(os.Args[0]),
	logPath:          logpath,
	clearHistoryLog:  false,
	logLevel:         "debug",
	listenAddr:       "127.0.0.1:0",
	encodeing:        "json",
	targetName:       "syslog",
	logFilePath:      "../log",
	ElkTemplateName:  "",
	traceIDExtractor: defaultTraceIDExtractor,
}

// LogOption 日志选项接口
type LogOption interface {
	apply(*logConf)
}

type logOptionFunc func(*logConf)

func (lf logOptionFunc) apply(option *logConf) {
	lf(option)
}

// ListenAddr 设置logserver的http端口,用来管理日志级别。
// 默认监听127.0.0.1下的随机端口
func ListenAddr(addr string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.listenAddr = addr
	})
}

// LogApiPath 设置logserver的api名字。
// 默认为 /log。
func LogApiPath(apipath string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.logPath = apipath
	})
}

// SetTarget 设置输出类型 stdout syslog asyncfile
func SetTarget(name string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.targetName = name
	})
}

// LogFilePath 设置输出路径，当 target = asyncfile 时需要此选项
func LogFilePath(path string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.logFilePath = path
	})
}

// ClearHistoryLog 启动前清理历史的日志文件
func ClearHistoryLog(clear bool) LogOption {
	return logOptionFunc(func(conf *logConf) {
		conf.clearHistoryLog = clear
	})
}

// LogLevel 日志级别
func LogLevel(level string) LogOption {
	return logOptionFunc(func(conf *logConf) {
		conf.logLevel = level
	})
}

// LogFileRotate 设置日志文件归档周期，仅支持 hour date.
func LogFileRotate(r string) LogOption {
	return logOptionFunc(func(option *logConf) {
		if r == "hour" || r == "date" {
			option.logFileRotate = r
		}
	})
}

// SetEncode 设置日志编码格式：tjson json console.
// 默认为json
func SetEncode(enc string) LogOption {
	return logOptionFunc(func(option *logConf) {
		if enc == "json" || enc == "console" || enc == "tjson" {
			//fmt.Println("set encode",enc)
			option.encodeing = enc
		} else {
			option.encodeing = "json"
		}

	})
}

// ProcessName 设置输出的进程名字。
// 默认去当前执行文件的名字。
func ProcessName(pname string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.processName = pname
	})
}

// TestEnv 设置是否测试环境。
// 默认为true,测试环境。
func TestEnv(yes bool) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.testenv = yes
	})
}

// HostName 设置日志机器的ip地址,方便定位。
// 默认不输出。
func HostName(hostname string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.HostName = hostname
	})
}

// ElkTmeplateName 用来设置输出到elk中的唯一名字。
// 默认不输出。
func ElkTmeplateName(name string) LogOption {
	return logOptionFunc(func(option *logConf) {
		option.ElkTemplateName = name
	})
}

// LogTimestampWithMs 设置 timestamp 字段是否展示毫秒部分，如 yyyy-MM-dd HH:mm:ss.SSS
func LogTimestampWithMs(yes bool) LogOption {
	return logOptionFunc(func(conf *logConf) {
		conf.logTimestampMs = yes
	})
}

// FunctionKey 设置专门的字段打印调用者函数名
//
//	例如 functionKey = "func", 则最终输出形如："func" : "functionA"
//	注意：默认的 caller 字段中已经包含了函数名，这里设置新的函数名字段主要用于云日志做索引
func FunctionKey(functionKey string) LogOption {
	return logOptionFunc(func(conf *logConf) {
		conf.functionKey = functionKey
	})
}

// TraceIDExtractor 提取traceID
func TraceIDExtractor(f func(ctx context.Context) string) LogOption {
	return logOptionFunc(func(conf *logConf) {
		conf.traceIDExtractor = f
	})
}
